package br.com.afi.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

/**
 * Métodos utilitários para manipulação de arquivos.
 * 
 * @author André de Fontana Ignacio
 * @version 1.0
 */
public class FileUtil
{
	/**
	 * Obtém a extensão do arquivo.
	 * 
	 * @param file Arquivo
	 * @return Extensão do arquivo
	 */
	public static String getExtension( File file )
	{
		return getExtension( file.getName() );
	}

	/**
	 * Obtém a extensão do nome do arquivo.
	 * 
	 * @param filename Nome do arquivo
	 * @return Extensão do arquivo
	 */
	public static String getExtension( String filename )
	{
		final StringTokenizer strTok = new StringTokenizer( filename, "." );
		String ext = "";
		while ( strTok.hasMoreTokens() )
		{
			ext = strTok.nextToken();
		}

		return ext.equals( filename ) ? "" : ext;
	}

	/**
	 * Obtém o nome do arquivo sem a extensão.
	 * 
	 * @param file Arquivo
	 * @return Nome do arquivo sem a extensão
	 */
	public static String getFileNameWihoutExtension( File file )
	{
		final String filename = file.getName();
		return getFileNameWihoutExtension( filename );
	}

	/**
	 * Obtém o nome do arquivo sem a extensão.
	 * 
	 * @param filename Nome do arquivo
	 * @return Nome do arquivo sem a extensão
	 */
	public static String getFileNameWihoutExtension( String filename )
	{
		final String aux[] = filename.split( "." );
		final StringBuilder sb = new StringBuilder();
		final String ret = filename;
		if ( aux.length > 1 )
		{
			for ( int i = 0; i < aux.length - 1; i++ )
			{
				sb.append( aux[i] );
			}
		}
		return ret;
	}

	/**
	 * Preenche o arquivo com os dados de um InputStream, esse método fecha a inputStream se for
	 * requisitado.
	 * 
	 * @param file Arquivo a ser populado
	 * @param is Stream com os dados
	 * @param closeInputStream Fecha a inputStream?
	 * @throws IOException Lançada quando não for possível ler o stream informado
	 */
	public static void fillFile( File file, InputStream is, boolean closeInputStream ) throws IOException
	{
		final FileOutputStream fos = new FileOutputStream( file );
		int data;
		try
		{
			while ( ( data = is.read() ) != -1 )
			{
				fos.write( data );
			}
		}
		finally
		{
			fos.flush();
			fos.close();
			if ( closeInputStream )
			{
				is.close();
			}
		}
	}

	/**
	 * Separa o nome do arquivo de um path.
	 * 
	 * @param path Caminho
	 * @param pathSeparator Separador do Path
	 * @return Nome do arquivo
	 */
	public static String getFilename( String path, String pathSeparator )
	{
		final String aux[] = path.split( pathSeparator );
		return aux[aux.length - 1];
	}

	/**
	 * Obtém o nome do diretório de arquivos temporários
	 * 
	 * @return Nome do diretório de arquivos temporários
	 */
	public static String getTemporaryDirectoryName()
	{
		String tempDir = System.getProperty( "java.io.tmpdir" );
		final String fileSeparator = File.separator;
		if ( !tempDir.endsWith( fileSeparator ) )
		{
			tempDir = tempDir + fileSeparator;
		}
		return tempDir;
	}

	/**
	 * Obtém o diretório de arquivos temporários
	 * 
	 * @return Diretório de arquivos temporários
	 */
	public static File getTemporaryDirectory()
	{
		return new File( getTemporaryDirectoryName() );
	}

	/**
	 * Obtém o conteúdo do arquivo, caso ocorra algum erro durante a leitura do arquivo lança
	 * RuntimeException.
	 * 
	 * @param file Arquivo
	 * @return Conteúdo do Arquivo
	 */
	public static String getContentRTE( File file )
	{
		try
		{
			return getContent( file );
		}
		catch ( Exception e )
		{
			throw new RuntimeException( e );
		}
	}

	/**
	 * Obtém o conteúdo do arquivo.
	 * 
	 * @param file Arquivo
	 * @return Conteúdo do Arquivo
	 * @throws IOException Lançada quando ocorrer algum problema na leitura do arquivo.
	 */
	public static String getContent( File file ) throws IOException
	{
		final StringBuilder content = new StringBuilder();

		final FileReader reader = new FileReader(file);
		final BufferedReader br = new BufferedReader( reader );
		String line = null;
		while ( ( line = br.readLine() ) != null )
		{
			content.append( line );
		}

		return content.toString();
	}

	/**
	 * Obtém o conteúdo da stream, caso ocorra algum erro durante a leitura da stream lança
	 * RuntimeException.
	 * 
	 * @param is Stream
	 * @return Conteúdo do Arquivo
	 */
	public static String getContentRTE( InputStream is )
	{
		try
		{
			return getContent( is );
		}
		catch ( Exception e )
		{
			throw new RuntimeException( e );
		}
	}

	/**
	 * Obtém o conteúdo da stream,
	 * 
	 * @param is Stream
	 * @return Conteúdo do Arquivo
	 * @throws IOException Lançada quando ocorrer algum problema na leitura da stream.
	 */
	public static String getContent( InputStream is ) throws IOException
	{
		final StringBuilder content = new StringBuilder();
		final InputStreamReader isr = new InputStreamReader( is );
		final BufferedReader br = new BufferedReader( isr );
		String line = null;
		while ( ( line = br.readLine() ) != null )
		{
			content.append( line );
		}

		return content.toString();
	}

	/**
	 * Obtém os bytes de um arquivo.
	 * 
	 * @param file Arquivo
	 * @return Bytes do Arquivo
	 * @throws IOException Lançada quando não for possível ler o arquivo
	 */
	public static byte[] getBytes( File file ) throws IOException
	{
		final InputStream is = new FileInputStream( file );

		final long length = file.length();
		final byte[] bytes = new byte[( int ) length];

		int offset = 0;
		int numRead = 0;
		while ( offset < bytes.length && ( numRead = is.read( bytes, offset, bytes.length - offset ) ) >= 0 )
		{
			offset += numRead;
		}

		if ( offset < bytes.length )
		{
			throw new IOException( "Não foi possível completar a leitura do arquivo " + file.getName() );
		}
		is.close();
		return bytes;
	}
}
